package org.brisling.service.auth.shiro;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.brisling.NoEntityDomain.sysman.SimpleResponseObj;
import org.brisling.config.common.exception.SessionExpiredException;
import org.brisling.config.common.exception.UserameOrPasswordWrongException;
import org.brisling.domain.sysman.Users;
import org.brisling.repository.sysman.inf.UsersRepo;
import org.brisling.vdomain.sysman.VPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;


@RestController
public class ShiroSecurityService {

	@Autowired
	private UsersRepo userRepo;
	
	private String mainPage="/biz/main.action";
	
	@Autowired
	private EntityManager entityManager;
	
	private static final Log log = LogFactory.getLog(ShiroSecurityService.class);
	
	@RequestMapping("/login")
	@ResponseBody
	public Object sysLogin(@RequestParam(value="loginname",required=false) String username,
						@RequestParam(value="password",required=false) String password,
						@RequestParam(value="remenberme",required=false) Boolean isRememberMe,
						@RequestBody String body) throws UserameOrPasswordWrongException{
		
		if(isRememberMe==null)			
			isRememberMe = false;
		
		
		
		
		UsernamePasswordToken token = new UsernamePasswordToken(username, password, isRememberMe);
        try {
        	Subject subject = SecurityUtils.getSubject();
        	subject.login(token);
        } catch (AuthenticationException e) {
            log.error( "error.login.generic, Invalid username or password.  Please try again." );
            throw new UserameOrPasswordWrongException();
        }
        
        SimpleResponseObj so = new SimpleResponseObj();
//        return SecurityUtils.getSubject().getPrincipal();
        so.setRetStr(mainPage);
        return so;
	}
	
	
	/**
	 * 
	 * @return 生成的password salt 值
	 */
	@RequestMapping("/generateSalt")
	@ResponseBody
	public String generateSalt(){
		
		return new SecureRandomNumberGenerator().nextBytes().toHex();
	}
	
	/**
	 * 
	 * @param username 用户名称
	 * @param password 用户密码
	 * @param uid	          用户编号
	 * @param salt		密码盐值
	 * @return	盐值为username+uid+salt ,sha256Hash方法，加密的password值
	 */
	@RequestMapping("/generatePassword")
	@ResponseBody
	public Object generatePassword(@RequestParam(value="loginname",required=false) String username,
			@RequestParam(value="password",required=false) String password,
			@RequestParam(value="uid",required=false) String uid,@RequestParam(value="salt",required=false) String salt){
		
		String _salt = new SecureRandomNumberGenerator().nextBytes().toHex();
		//_salt = "50e314d581d4a4a88233c1700ec64691";
		
		
		
		return new SimpleHash(Sha256Hash.ALGORITHM_NAME,password,ByteSource.Util.bytes(username+uid+_salt),1);
		
		//return new Sha256Hash(password,ByteSource.Util.bytes(username+uid+salt)).toHex();
	}
	
	@RequestMapping(value="/main.action")
	public ModelAndView home(){
		return new ModelAndView("/biz/sitemain/home");
	}
	
	public Users getCurrentUser() {
		// TODO Auto-generated method stub
		final Long currentUserId = (Long) SecurityUtils.getSubject().getPrincipal();
        if( currentUserId != null ) {
            return userRepo.findOne(currentUserId);
        } else {
            return null;
        }
	}
	
	@RequestMapping("/logout")
	@ResponseBody
	public String sysLogout(){
		SecurityUtils.getSubject().logout();
		return "success";
	}
	
	/**
	 * 
	 * @return 用户具备访问权限的业务模块清单
	 * @throws Exception 
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping("/getPermissions")
	@ResponseBody
	public List<VPermission> getPermissions() throws SessionExpiredException{
		
		Users user= this.getCurrentUser();
		
		if(user==null)
			throw new SessionExpiredException();
		
		
		String sql = "SELECT DISTINCT p.id,p.parentid,p.name,p.iconcls,p.pageURL,p.bizcode";
		
		List<VPermission> permissionsList = null;
		if ("admin".equals(user.getName()))
		{
			sql+=String.format(" FROM Permissions AS p " +
					"where p.STATUS='A' and p.TYPE='F' and p.ISUSED='Y'");
			permissionsList = 
					entityManager.createNativeQuery(sql)						
						.getResultList();
		}
		else 
		{
			sql+=String.format(" FROM RolePermissionRelationDomain AS rp " +
					"INNER JOIN Roles AS r ON rp.biztid = r.id " +
					"INNER JOIN UserRoleRelationDomain AS ur ON rp.biztid = ur.bizeid " +
					"INNER JOIN Users AS u ON u.id = ur.biztid " +
					"INNER JOIN Permissions AS p ON rp.bizeid = p.id " +
					"WHERE p.STATUS='A' and p.TYPE='F' and p.ISUSED='Y' " +
					"and u.id= :userid");
			permissionsList = 
					entityManager.createNativeQuery(sql)
						.setParameter("userid", user.getId())
						.getResultList();
		}
		
		
		
		log.debug(sql);
         
 		
		List<VPermission> parentList=new ArrayList<VPermission>();
		for (Object object : permissionsList)
		{
			Object[] objs=(Object[])object;
			String id = String.valueOf(objs[0]);
			if (objs[1]==null)
			{
				VPermission menuModel=new VPermission();
				menuModel.setName(String.valueOf(objs[2]));
				menuModel.setIconcls(String.valueOf(objs[3]));
				menuModel.setPageUrl(String.valueOf(objs[4]));
				menuModel.setBizcode(String.valueOf(objs[5]));
				List<VPermission> childList=new ArrayList<VPermission>();
				for (Object obj2 : permissionsList)
				{
					VPermission menuChildModel=new VPermission();
					Object[] objs2=(Object[])obj2;
					String sid = String.valueOf(objs2[1]);
					if (sid.equals(id))
					{
						menuChildModel.setName(String.valueOf(objs2[2]));
						menuChildModel.setIconcls(String.valueOf(objs2[3]));
						menuChildModel.setPageUrl(String.valueOf(objs2[4]));
						menuChildModel.setBizcode(String.valueOf(objs2[5]));
						childList.add(menuChildModel);
					}
				}
				menuModel.setChild(childList);
				parentList.add(menuModel);
			}
		}
		return parentList;
	}
}
